package top.yueyazhui.account.service.impl;

import cn.hutool.core.util.ObjectUtil;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.yueyazhui.account.entity.Account;
import top.yueyazhui.account.mapper.AccountMapper;
import top.yueyazhui.account.service.AccountService;

import java.math.BigDecimal;

@Service
@Slf4j
public class AccountServiceImpl implements AccountService {

    @Autowired
    AccountMapper accountMapper;

    /**
     * 一阶段操作
     * 检查资源，如：检查账户是否存在，检查账户余额是否充足，余额充足的话，就冻结余额。
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean prepare(String userId, Double money) {
        Account account = accountMapper.getAccountByUserId(userId);
        if (ObjectUtil.isNull(account)) {
            throw new RuntimeException("账户不存在");
        }
        if (account.getMoney() < money) {
            throw new RuntimeException("账户余额不足，扣款失败");
        }
        // 冻结金额
        account.setFreezeMoney(account.getFreezeMoney() + money);
        account.setMoney(account.getMoney() - money);
        Integer result = accountMapper.updateAccount(account);
        log.info("{} 账户预扣款 {} 元", userId, money);
        return result == 1;
    }

    /**
     * 二阶段提交
     * 提交，主要是扣款操作（操作冻结金额即可）。
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean commit(BusinessActionContext businessActionContext) {
        // 获取 prepare 阶段的两个参数
        String userId = (String) businessActionContext.getActionContext("userId");
        Double money = ((BigDecimal) businessActionContext.getActionContext("money")).doubleValue();
        Account account = accountMapper.getAccountByUserId(userId);
        if (account.getFreezeMoney() < money) {
            throw new RuntimeException("账户余额不足，扣款失败");
        }
        account.setFreezeMoney(account.getFreezeMoney() - money);
        Integer result = accountMapper.updateAccount(account);
        log.info("{} 账户扣款 {} 元", userId, money);
        return result == 1;
    }

    /**
     * 二阶段回滚
     * 回滚，将冻结的金额复原（释放）。
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rollback(BusinessActionContext businessActionContext) {
        // 获取 prepare 阶段的两个参数
        String userId = (String) businessActionContext.getActionContext("userId");
        Double money = ((BigDecimal) businessActionContext.getActionContext("money")).doubleValue();
        Account account = accountMapper.getAccountByUserId(userId);
        if (ObjectUtil.isNull(account)) {
            log.info("{} 账户不存在", userId);
            return true;
        }
        if (account.getFreezeMoney() >= money) {
            account.setMoney(account.getMoney() + money);
            account.setFreezeMoney(account.getFreezeMoney() - money);
            Integer result = accountMapper.updateAccount(account);
            log.info("{} 账户释放冻结金额 {} 元", userId, money);
            return result == 1;
        }
        log.info("{} 账户不需要释放冻结金额", userId);
        return true;
    }
}
